package javase.ch02.sync;

import java.util.concurrent.TimeUnit;

/**
 * @Desc TODO
 * @Author chenmin
 * @Date 2025/10/30
 *
 * 一、同步代码块
 *    1.语法
 *      synchronized(对象锁){
 *          //线程同步代码
 *      }
 *
 *    2.对象锁   任何一个对象都可以是对象锁，包括类
 *      2.1 this作为对象锁   who调用方法, who就是对象锁   搭配成员方法进行使用
 *          使用同一把锁(sync)，出现 "等待" 现象；
 *          使用不是同一把锁锁(sync1 、 sync2)，出现 "争抢" 现象；
 *      2.2 Xxx.class作为对象锁 即类锁   搭配静态法进行使用
 *          使用同一把锁(sync)，出现 "等待" 现象；
 *          使用不是同一把锁锁(sync1 、 sync2)，出现 "等待" 现象；
 *      2.3 "A"作为对象锁     在字符串常量池中分配内存空间，同一把锁
 *          使用同一把锁(sync)，出现 "等待" 现象；
 *          使用不是同一把锁锁(sync1 、 sync2)，出现 "等待" 现象；
 *      2.4 byte[] lock = new byte[0]作为对象锁  当作为属性时，效果等同于this作为对象锁
 *          使用同一把锁(sync)，出现 "等待" 现象；
 *          使用不是同一把锁锁(sync1 、 sync2)，出现 "争抢" 现象；
 */
public class SyncTest1 {

    //开销最小的锁
    private byte[] lock = new byte[0];

    public void m1(){
        synchronized (lock){
            for (int i = 0; i < 5; i++) {
                System.out.println(Thread.currentThread().getName()+" i = "+i);
                try {
                    TimeUnit.SECONDS.sleep(1);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }
        }
    }

    public void m2(){
        synchronized (lock){
            for (int i = 0; i < 5; i++) {
                System.out.println(Thread.currentThread().getName()+" i = "+i);
                try {
                    TimeUnit.SECONDS.sleep(1);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }
        }
    }

    public static void main(String[] args) {
        SyncTest1 sync1 = new SyncTest1();
        SyncTest1 sync2 = new SyncTest1();

        //同一把对象锁  sync
        //不是同一把对象锁 sync1  sync2
        Thread t1 = new Thread(() -> sync1.m1(), "线程1");
        Thread t2 = new Thread(() -> sync1.m2(), "线程2");

        t1.start();
        t2.start();

        //让主线程先沉睡，其实会让t1 、t2 副线程先行
        try {
            TimeUnit.SECONDS.sleep(5);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        System.out.println("t1 = "+t1.getState());
        System.out.println("t2 = "+t2.getState());
    }

}
